/*
 * nsap_deid.c
 *
 *  Created on: 2015年5月12日
 *      Author: LiJie
 */

#include <stdio.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>
#include <uuid/uuid.h>
#include <stdint.h>
#include "log.h"
#include "devid.h"

typedef struct { 
	int8_t LJ[2];
	int16_t version;
	int16_t offset;
} nsap_deid_block_t;

int8_t S_deid_enable[8][8] = {
		{0, 1, 0, 0, 0, 0, 1, 0},
		{0, 0, 1, 0, 1, 0, 0, 0},
		{0, 1, 0, 1, 0, 0, 0, 1},
		{0, 0, 0, 0, 1, 1, 0, 0},
		{0, 0, 1, 0, 0, 0, 0, 0},
		{0, 1, 0, 0, 0, 0, 1, 0},
		{0, 0, 1, 0, 0, 1, 0, 0},
		{0, 0, 0, 1, 0, 0, 1, 0},
};

static char S_devid[40];


static int nsap_devid_read_mtdblock_name(char *mtd_name, const char *partition_name)
{
    FILE *fp;
    char line[128];
	int mtdidx = 0;

    if ((fp = fopen("/proc/mtd", "r")) == NULL)
        return -1;

    while (fgets(line, sizeof(line), fp) != NULL) {
        if (strstr(line, partition_name)) {
            if (strtok(line, ":")) {
				sscanf(line, "mtd%d", &mtdidx);
				if (mtdidx < 2) {
					fclose(fp);
					return -1;
				}
                sprintf(mtd_name, "/dev/mtdblock%d", mtdidx);
                fclose(fp);
                return 0;
            }
        }
    }
    fclose(fp);
    return -1;
}


static int nsap_devid_read(const char *filename)
{
	int i, j, n = 0;
	char row = 0;
	FILE *fp = NULL;
	uint16_t version = 0;
	uint8_t array[8][8];
	int8_t devidb[16] = { 0 };
	char devidtb[256];
	char buff[6] = { 0 };
	nsap_deid_block_t *block = NULL;

	if (!filename) {
		DEBUG("func(%s),function input args error", __FUNCTION__);
		return -1;
	}
	fp = fopen(filename, "r");
	if (!fp) {
		DEBUG("func(%s), fopen \"%s\" failed, %s",
				__FUNCTION__, filename, strerror(errno));
		return -1;
	}
	if (fread(buff, 6, 1, fp) < 1) {
		DEBUG("func(%s) (1)fread \"%s\" failed, %s",
				__FUNCTION__, filename, strerror(errno));
		fclose(fp);
		return -1;
	}
	block = (nsap_deid_block_t *) buff;
	if ('L' == block->LJ[0] && 'J' == block->LJ[1]) {
		if (1 == block->version && block->offset < 1024) {
			row = block->offset % 2;
			if (fseek(fp, (block->offset), SEEK_CUR)) {
				DEBUG("func(%s), fseek \"%s\" %d bytes failed, %s",
						__FUNCTION__, filename, block->offset, strerror(errno));
				fclose(fp);
				return -1;
			}
			for (i = 0; i < 8; ++i) {
				for (j = 0; j < 8; ++j) {
					if (row == 1) {
						if (fread(&(array[i][j]), 1, 1, fp) < 1) {
							DEBUG("func(%s), (2)fread \"%s\" failed, %s",
											__FUNCTION__, filename, strerror(errno));
							fclose(fp);
							return -1;
						}
					} else {
						if (fread(&(array[j][i]), 1, 1, fp) < 1) {
							DEBUG("func(%s), (2)fread \"%s\" failed, %s",
											__FUNCTION__, filename, strerror(errno));
							fclose(fp);
							return -1;
						}
					}
				}
			}
			for (i = 0, n = 0; i < 8; ++i) {
				for (j = 0; j < 8; ++j) {
					if (row == 1) {
						if (S_deid_enable[i][j] == 1) {
							devidb[n++] = array[i][j];
						}
					} else {
						if (S_deid_enable[j][i] == 1) {
							devidb[n++] = array[j][i];
						}
					}
				}
			}
			fclose(fp);
			memset(devidtb, 0, sizeof(devidtb));
			uuid_unparse_upper(devidb, devidtb);
			DEBUG("Device-Ident : \"%s\"", devidtb);
			memset(S_devid, 0, sizeof(S_devid));
			if (!strncpy(S_devid, devidtb, NSAP_DEVID_SIZE)) {
				DEBUG("func(%s), Device-Id new string failed, %s",
						__FUNCTION__, strerror(errno));
				return -1;
			}
			return 0;
		}
	} else {
		DEBUG("func(%s), file \"%s\" is not match format",
				__FUNCTION__, filename);
	}
	fclose(fp);
	return -1;
}

static int nsap_devid_write(const char *filename)
{
	int i, j, n = 0;
	int8_t tmp = 0;
	int8_t array[8][8];
	char devidtb[256];
	uuid_t deidb;
	int16_t version = 1;
	int16_t offset;
	char row = 0;
	FILE *fp = NULL;

	if (!filename) {
		DEBUG("func(%s), function input args error", __FUNCTION__);
		return -1;
	}

	uuid_clear(deidb);
	uuid_generate(deidb);
	if (uuid_is_null(deidb)) {
		DEBUG("func(%s), create UUID failed", __FUNCTION__);
		return -1;
	}

	fp = fopen(filename, "w");
	if (!fp) {
		DEBUG("func(%s), fopen \"%s\" failed, %s",
				__FUNCTION__, filename, strerror(errno));
		return -1;
	}
	srand(time(NULL));
	offset = (int16_t)(rand() % 1024);
	row = offset % 2;
	if (fwrite("LJ", 2, 1, fp) < 1) {
		DEBUG("func(%s), (1)fwrite \"%s\" failed, %s",
				__FUNCTION__, filename, strerror(errno));
		fclose(fp);
		return -1;
	}
	if (fwrite(&version, 2, 1, fp) < 1) {
		DEBUG("func(%s), (2)fwrite \"%s\" failed, %s",
				__FUNCTION__, filename, strerror(errno));
		fclose(fp);
		return -1;
	}
	if (fwrite(&offset, 2, 1, fp) < 1) {
		DEBUG("func(%s), (3)fwrite \"%s\" failed, %s",
				__FUNCTION__, filename, strerror(errno));
		fclose(fp);
		return -1;
	}
	for (i = 0; i < offset; ++i) {
		tmp = (uint8_t)(rand() % 256);
		if (fwrite(&tmp, 1, 1, fp) < 1) {
			DEBUG("func(%s), (4)fwrite \"%s\" failed, %s",
					__FUNCTION__, filename, strerror(errno));
			fclose(fp);
			return -1;
		}
	}
	for (i = 0, n = 0; i < 8; ++i) {
		for (j = 0; j < 8; ++j) {
			if (1 == row) {
				if (1 == S_deid_enable[i][j]) {
					if (fwrite(&(deidb[n++]), 1, 1, fp) < 1) {
						DEBUG("func(%s), (5)fwrite \"%s\" failed, %s",
								__FUNCTION__, filename, strerror(errno));
						fclose(fp);
						return -1;
					}
				} else {
					tmp = (int8_t) (rand() % 256);
					if (fwrite(&tmp, 1, 1, fp) < 1) {
						DEBUG("func(%s), (6)fwrite \"%s\" failed, %s",
								__FUNCTION__, filename, strerror(errno));
						fclose(fp);
						return -1;
					}
				}
			} else {
				if (1 == S_deid_enable[j][i]) {
					if (fwrite(&(deidb[n++]), 1, 1, fp) < 1) {
						DEBUG("func(%s), (7)fwrite \"%s\" failed, %s",
								__FUNCTION__, filename, strerror(errno));
						fclose(fp);
						return -1;
					}
				} else {
					tmp = (int8_t) (rand() % 256);
					if (fwrite(&tmp, 1, 1, fp) < 1) {
						DEBUG("func(%s), (8)fwrite \"%s\" failed, %s",
								__FUNCTION__, filename, strerror(errno));
						fclose(fp);
						return -1;
					}
				}
			}
		}
	}
	fclose(fp);
	memset(devidtb, 0, sizeof(devidtb));
	uuid_unparse_upper(deidb, devidtb);
	DEBUG("Device-Ident : \"%s\"", devidtb);
	memset(S_devid, 0, sizeof(S_devid));
	if (!strncpy(S_devid, devidtb, NSAP_DEVID_SIZE)) {
		DEBUG("func(%s), Device-Id new string failed, %s",
				__FUNCTION__, strerror(errno));
		return -1;
	}
	return 0;
}

int nsap_devid_init(void)
{
#if NSAP_DEVID_DEBUG
	char mtd_name[] = "./nsap_dev_id.conf";
#else
	char mtd_name[64] = { 0 };
	memset(S_devid, 0, sizeof(S_devid));
	if (nsap_devid_read_mtdblock_name(mtd_name, NSAP_DEVID_MTD_NAME)) {
		memset(mtd_name, 0, sizeof(mtd_name));
		memcpy(mtd_name, "/dev/natshell", 14);
//		DEBUG("func(%s), find MTD partition failed", __FUNCTION__);
//		return -1;
	}
#endif

	if (nsap_devid_read(mtd_name)) {
		DEBUG("func(%s), read deid from \"%s\" failed", __FUNCTION__, mtd_name);
		if (nsap_devid_write(mtd_name)) {
			DEBUG("func(%s), write deid from \"%s\" failed", __FUNCTION__, mtd_name);
			return -1;
		}
	}
	return 0;
}

char *nsap_devid_get(void)
{
	return S_devid;
}

void nsap_devid_free(void)
{
}

